#include "app_bt.h"
#include <string.h>
#include "log.h"
#include "app_serial.h"
#include <unistd.h>
#include <fcntl.h>

static char bt_send_header[] = {0x41, 0x54, 0x2b, 0x4d, 0x45, 0x53, 0x48, 0x00};
static char bt_send_tailer[] = {0x0d, 0x0a};
static char bt_receive_header[] = {0xf1, 0xdd};

/**
 * @brief 蓝牙初始化配置
 * @param device 设备信息
 * @return int 0：成功，其他：失败
 * @note 设置预处理方法  2 （写前、读后）\
 * 设置蓝牙相关的参数默认值（波特率，网络ID，网络段地址，网络名）
 */
int app_bt_init(device_t *device)
{
    device->post_read = app_bt_post_read;
    device->priv_write = app_bt_pre_write;
    // 默认设置参数
    app_bt_set_default_all(device);

    return 0;
}

/**
 * @brief 蓝牙写前预处理
 * @param 处理前的 数据
 * @param 处理前的 数据长度
 * @return 预处理后的数据长度
 */
int app_bt_pre_write(char *data, int data_len)
{
    char data_new[100];
    int id_len = data[1];
    int msg_len = data[2];

    // h帧头
    memcpy(data_new, bt_send_header, 8);
    // id
    memcpy(data_new + 8, data + 3, id_len);
    // msg
    memcpy(data_new + 8 + id_len, data + 3 + id_len, msg_len);
    // 结尾
    memcpy(data_new + 8 + id_len + msg_len, bt_send_tailer, 2);

    int data_new_len = 8 + id_len + msg_len + 2;

    // 覆盖原始数据
    memcpy(data, data_new, data_new_len);

    return data_new_len;
}

/**
 * @brief 蓝牙读后预处理
 * @param 处理后的 数据
 * @param 处理后的 数据长度
 * @return 预处理后的数据长度
 *
 * @note 把收到的数据加入缓冲区 \
 * 先看当前缓冲区的总数据量够不够 至少有8个数据\
 * 如果够8个数据 \
 * 要从缓冲区中逐个的找到 帧头 f1 dd \
 * 如果找到帧头 清理掉帧头之前的数据 \
 * 清理后是否够8个数据 取帧头后的第一个字节 标识了之后数据的长度 根据此长度取数据 \
 * 如果有整帧数据 则把整帧数据拷贝到data中 （需要拼接） \
 * 把该条数据从缓冲区中删除 调整缓冲区长度 \
 * 返回数据长度
 */

static char data_buff[100];
static int data_buff_len = 0;

// 从缓冲区清理指定长度的数据
static void app_bt_clear_data_buff(int len)
{
    memmove(data_buff, data_buff + len, data_buff_len - len);
    data_buff_len -= len;
}

int app_bt_post_read(char *data, int data_len)
{
    // 把收到的数据加入缓冲区
    memcpy(data_buff + data_buff_len, data, data_len);
    data_buff_len += data_len;
    // 先看当前缓冲区的总数据量够不够 至少有8个数据
    if (data_buff_len < 8)
    {
        return 0;
    }
    // 如果够8个数据 要从缓冲区中逐个的找到 帧头 f1 dd
    for (int i = 0; i < data_buff_len - 1; i++)
    {
        if (data_buff[i] == bt_receive_header[0] && data_buff[i + 1] == bt_receive_header[1])
        {
            // 如果找到帧头 清理掉帧头之前的数据
            app_bt_clear_data_buff(i);
        }
    }
    // 清理后不足8个数据 ，退出
    if (data_buff_len < 8)
    {
        return 0;
    }

    // 清理后是否够8个数据 取第三个字节 标识了之后数据的长度 根据此长度取数据
    int len_after_header = data_buff[2];
    // 如果不足8个数据 ，退出
    if (data_buff_len < 3 + len_after_header)
    {
        return 0;
    }
    // 如果有整帧数据 则把整帧数据拷贝到data中 （需要拼接）
    data[0] = CONN_TYPE_BT;
    data[1] = 2;
    data[2] = len_after_header - 4; // 减去2个地址长度
    memcpy(data + 3, data_buff + 3, 2);
    memcpy(data + 3 + 2, data_buff + 7, data[2]);
    // 把该条数据从缓冲区中删除 调整缓冲区长度
    app_bt_clear_data_buff(3 + len_after_header);
    // 返回数据长度
    int new_data_len = 3 + 2 + data[2];

    return new_data_len;
}

static int app_bt_wait_ack(device_t *device)
{
    // 等待50毫秒
    usleep(1000 * 50);
    // 读取设备文件中的值
    char data_buff[4]; // 就是 ok/r/n
    // int ret = read(device->dev_fd, data_buff, 100);
    read(device->dev_fd, data_buff, 4);
    //
    if (memcmp(data_buff, "OK\r\n", 4) == 0)
    {
        return 0;
    }
    return -1;
}

/**
 * @brief 蓝牙做连通性测试 AT/r/n
 * @param device 设备信息
 * @return int 0：成功，其他：失败
 */
int app_bt_status(device_t *device)
{
    // 声明一个命令字符串
    char *cmd = "AT\r\n";
    // 把字符串写入串口设备文件中 write
    // int ret = write(device->dev_fd, cmd, strlen(cmd));
    write(device->dev_fd, cmd, strlen(cmd));
    // 等待并且获取返回值
    return app_bt_wait_ack(device);
}

/**
 * @brief 重启  reset AT+RESET/r/n
 * @param device 设备信息
 * @return int 0：成功，其他：失败
 */
int app_bt_reset(device_t *device)
{
    // 声明一个命令字符串
    char *cmd = "AT+RESET\r\n";
    // 把字符串写入串口设备文件中 write
    // int ret = write(device->dev_fd, cmd, strlen(cmd));
    write(device->dev_fd, cmd, strlen(cmd));
    // 等待并且获取返回值
    return app_bt_wait_ack(device);
}

/**
 * @brief 设置波特率 AT+BAUD?/r/n
 * @param baudrate 波特率
 * @return int 0：成功，其他：失败
 */
int app_bt_set_baudrate(device_t *device, BT_BAUD_RATE baudrate)
{
    // 声明一个命令字符串
    char cmd[20];
    sprintf(cmd, "AT+BAUD%d\r\n", baudrate);
    // 把字符串写入串口设备文件中 write
    // int ret = write(device->dev_fd, cmd, strlen(cmd));
    write(device->dev_fd, cmd, strlen(cmd));
    // 等待并且获取返回值
    return app_bt_wait_ack(device);
}

/**
 * @brief 设置网络ID AT+NETID?/r/n
 * @param netid 网络ID
 * @return int 0：成功，其他：失败
 */
int app_bt_set_netid(device_t *device, char *netid)
{
    // 声明一个命令字符串
    char cmd[20];
    sprintf(cmd, "AT+NETID%s\r\n", netid);
    // 把字符串写入串口设备文件中 write
    // int ret = write(device->dev_fd, cmd, strlen(cmd));
    write(device->dev_fd, cmd, strlen(cmd));
    // 等待并且获取返回值
    return app_bt_wait_ack(device);
}

/**
 * @brief 设置网络段地址 AT+MADDR?/r/n
 * @param maddr 网络段地址
 * @return int 0：成功，其他：失败
 */
int app_bt_set_maddr(device_t *device, char *maddr)
{
    // 声明一个命令字符串
    char cmd[20];
    sprintf(cmd, "AT+MADDR%s\r\n", maddr);
    // 把字符串写入串口设备文件中 write
    // int ret = write(device->dev_fd, cmd, strlen(cmd));
    write(device->dev_fd, cmd, strlen(cmd));
    // 等待并且获取返回值
    return app_bt_wait_ack(device);
}

/**
 * @brief 设置网络名 AT+NAME?/r/n
 * @param name 网络名
 * @return int 0：成功，其他：失败
 */
int app_bt_set_name(device_t *device, char *name)
{
    // 声明一个命令字符串
    char cmd[20];
    sprintf(cmd, "AT+NAME%s\r\n", name);
    // 把字符串写入串口设备文件中 write
    // int ret = write(device->dev_fd, cmd, strlen(cmd));
    write(device->dev_fd, cmd, strlen(cmd));
    // 等待并且获取返回值
    return app_bt_wait_ack(device);
}

/**
 * @brief 设置整体的默认值
 */
int app_bt_set_default_all(device_t *device)
{
    // 要考虑首次设置时 主控芯片和蓝牙芯片的波特率不一致 要对两者的连通性进行测试
    // 如果不一致 还要进行调整  波特率  再设其他值测试
    // 1 要调整串口的阻塞模式  改为非阻塞的 然后进行测试
    app_serial_set_block(device, 0);
    // 2 进行连通性测试 在此之前波特率已经是115200 如果测试不通过 -> 蓝牙芯片的波特率 9600
    if (app_bt_status(device) != 0)
    {
        // 3 如果测试不通过 把主控芯片的串口改为9600 进行测试
        app_serial_set_baud(device, BR_9600);
        tcflush(device->dev_fd, TCIOFLUSH);
        
        if (app_bt_status(device) != 0)
        {
            log_error("改为波特率 9600 依然不通过");
            return -1;
        }
        // 4 如果测试通过 向蓝牙芯片发送命令 设置波特率 为115200  
        // 同时重启蓝牙芯片（等待两秒）  修改 主控芯片的波特率 为115200 
        // 再进行一次连通性测试
        int ret = app_bt_set_baudrate(device, BT_BAUD_115200);
        if (ret != 0)
        {
            log_error("设置波特率失败");
            return -1;
        }
        ret = app_bt_reset(device);
        if (ret == 0)
        {
            log_info("重启蓝牙芯片成功");
        }
        else
        {
            log_error("重启蓝牙芯片失败");
            return -1;
        }
        sleep(2);
        app_serial_set_baud(device, BR_115200);
        tcflush(device->dev_fd, TCIOFLUSH);
        if (app_bt_status(device) != 0)
        {
            log_error("设置波特率 115200 依然不通过");
            return -1;
        }
    }

    // 5 如果测试通过，则进行其他设置 
    // 其他设置：设备名称，网络id 网络段地址
    app_bt_set_name(device, "bsh_BT");
    app_bt_set_netid(device, "0010");
    app_bt_set_maddr(device, "0011");
    // 6 串口恢复为阻塞模式
    app_serial_set_block(device, 1);

    return 0;
}